﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Security.Cryptography;
using mesoBoard.Data;
using mesoBoard.Data.Repositories;
using System.Web.Security;
using System.Text.RegularExpressions;
using System.Collections;
using System.Web.Mvc;

namespace mesoBoard.Services
{
    public class Users : IUsers
    {
        private HttpServerUtility Server = HttpContext.Current.Server;
        private IRepositoriesWrapper Repositories;

        public Users(IRepositoriesWrapper repos)
        {
            this.Repositories = repos;
        }

        public User CurrentUser
        {
            get
            {
                    return GetUser();
            }
        }

        public void SessionStart(string ipAddress)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
                LogoutRoutine(int.Parse(HttpContext.Current.User.Identity.Name));
            else
                Repositories.OnlineUsers.DeleteOnlineGuest(ipAddress);
        }

        public void SessionEnd(string ipAddress)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
                LogoutRoutine(int.Parse(HttpContext.Current.User.Identity.Name));
            else
                Repositories.OnlineUsers.DeleteOnlineGuest(ipAddress);
        }

        public bool ActivateUser(string userName, string activationCode)
        {
            if (!UserExists(userName))
                return false;

            User theUser = GetUser(userName);

            if (string.IsNullOrEmpty(theUser.ActivationCode))
                return true;

            if (theUser.ActivationCode == activationCode)
            {
                theUser.ActivationCode = string.Empty;
                Repositories.Users.UpdateUser(theUser);
                return true;
            }
            else
                return false;
        }

        public bool UserExists(string userNameorID)
        {
            if (string.IsNullOrWhiteSpace(userNameorID))
                return false;

            int userID;
            User TheUser;
            bool IsInt = int.TryParse(userNameorID, out userID);
            if (IsInt)
                TheUser = Repositories.Users.GetUser(userID);
            else
                TheUser = Repositories.Users.GetUser(userNameorID);

            return TheUser != null;
        }

        public bool ValidatePassword(string userName, string password)
        {
            User TheUser = GetUser(userName);
            return ValidatePassword(TheUser, password);

        }

        public bool ValidatePassword(int userID, string password)
        {
            User TheUser = GetUser(userID);
            return ValidatePassword(TheUser, password);
        }

        public bool ValidatePassword(User theUser, string password)
        {
            string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password + theUser.PasswordSalt, "MD5");
            return theUser.Password == hashedPassword;
        }

        public bool EmailInUse(string email)
        {
            return Repositories.Users.EmailInUse(email);
        }

        public void LoginRoutine(User theUser, string ipAddress)
        {
            Repositories.Users.UpdateLastLogin(theUser.UserID, ipAddress);
            if(Repositories.OnlineUsers.GetOnlineGuest(ipAddress) != null)
                Repositories.OnlineUsers.DeleteOnlineGuest(ipAddress);
            OnlineUser oUser = Repositories.OnlineUsers.GetOnlineUser(theUser.UserID);
            if (oUser == null)
            {
                Repositories.OnlineUsers.CreateOnlineUser(new OnlineUser
                {
                    Date = DateTime.UtcNow,
                    UserID = theUser.UserID
                });
            }
            else
            {
                oUser.Date = DateTime.UtcNow;
                Repositories.OnlineUsers.UpdateOnlineUser(oUser);
            }

            Repositories.Threads.DeleteViews(theUser.UserID);
        }

        public void LogoutRoutine(int userID)
        {
            Repositories.Threads.DeleteViews(userID);
            Repositories.OnlineUsers.DeleteOnlineUser(userID);
        }

        public User GetUser()
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
                return GetUser(int.Parse(HttpContext.Current.User.Identity.Name));
            else
                return null;
        }

        public User GetUser(int userID)
        {
            return Repositories.Users.GetUser(userID);
        }

        public User GetUser(string userNameORemail)
        {
            if (EmailInUse(userNameORemail))
                return Repositories.Users.GetUserByEmail(userNameORemail);
            else
                return Repositories.Users.GetUser(userNameORemail);
        }

        public string ResetPassword(int userID)
        {
            User TheUser = GetUser(userID);

            string NewPass = Randoms.RandomPassword();
            string Salt = Randoms.CreateSalt();
            string HashedPass = FormsAuthentication.HashPasswordForStoringInConfigFile(NewPass + Salt, "MD5");

            TheUser.Password = HashedPass;
            TheUser.PasswordSalt = Salt;

            Repositories.Users.UpdateUser(TheUser);

            return NewPass;
        }

        public void UpdatePassword(int userID, string newPassword)
        {
            string newSalt = Randoms.CreateSalt();
            string newHashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(newPassword + newSalt, "MD5");

            User TheUser = GetUser(userID);

            TheUser.Password = newHashedPassword;
            TheUser.PasswordSalt = newSalt;

            Repositories.Users.UpdateUser(TheUser);
        }

        public void UpdateProfile(UserProfile TheProfile)
        {
            UserProfile userProfile = Repositories.Users.GetUser(TheProfile.UserID).UserProfile;
            userProfile.AlwaysShowSignature = TheProfile.AlwaysShowSignature;
            userProfile.Location =  TheProfile.Location;
            userProfile.ThemeID = TheProfile.ThemeID;
            userProfile.DefaultRole = TheProfile.DefaultRole == 0 ? null : TheProfile.DefaultRole;
            userProfile.AIM = TheProfile.AIM;
            userProfile.ICQ = TheProfile.ICQ;
            userProfile.MSN = TheProfile.MSN;
            userProfile.Website = TheProfile.Website;
            userProfile.Birthdate = TheProfile.Birthdate;
            userProfile.AlwaysSubscribeToThread = TheProfile.AlwaysSubscribeToThread;
            Repositories.Users.UpdateProfile(userProfile);
        }

        public void Register(User theUser)
        {
            string ActivationType = SiteConfig.AccountActivation.Value;
            string Salt = Randoms.CreateSalt() + DateTime.UtcNow.ToString();
            theUser.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(theUser.Password + Salt, "MD5");
            theUser.PasswordSalt = Salt;
            theUser.RegisterDate = DateTime.UtcNow;
            theUser.RegisterIP = HttpContext.Current.Request.UserHostAddress;
            theUser.ActivationCode = ActivationType == "None" ? string.Empty : Randoms.CleanGUID();
            theUser.Status = false;
            theUser.LastLoginIP = null;
            theUser.UsernameLower = theUser.Username.ToLower();
            theUser.RegisterDate = DateTime.UtcNow;
            theUser.LastLoginDate = DateTime.UtcNow;
            theUser.LastLogoutDate = DateTime.UtcNow;
            theUser.LastPostDate = DateTime.UtcNow;

            Repositories.Users.CreateUser(theUser);
        }

        public string RequestPasswordReset(int userID)
        {
            if (Repositories.Users.GetPasswordResetRequest(userID) != null)
                Repositories.Users.DeletePasswordResetRequest(userID);

            PasswordResetRequest pwrr = new PasswordResetRequest{
                UserID = userID,
                Token = Randoms.CleanGUID(),
                Date = DateTime.UtcNow
            };

            Repositories.Users.CreatePasswordResetRequest(pwrr);

            string token = userID.ToString() + "-" + pwrr.Token;

            return token;
        }

        public bool ValidatePasswordResetRequest(string token)
        {
            if (string.IsNullOrWhiteSpace(token))
                return false;

            string[] split = token.Split('-');
            int userID = int.Parse(split[0]);
            string code = split[1];

            PasswordResetRequest pwrr = Repositories.Users.GetPasswordResetRequest(userID);

            if ((DateTime.UtcNow - pwrr.Date).Minutes > 15)
                return false;

            return (pwrr.UserID == userID && pwrr.Token == code);
        }

        public void DeletePasswordResetRequest(int userID)
        {
            Repositories.Users.DeletePasswordResetRequest(userID);
        }
    }
}
